Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace checkers with validators #36

Merged
merged 3 commits into from
Sep 25, 2018
Merged

Conversation

ziima
Copy link
Collaborator

@ziima ziima commented Sep 14, 2018

Refs #35

I've tried to transform the checkers to validators. Comments are welcome.

@pawamoy
Copy link
Owner

pawamoy commented Sep 14, 2018

Wow. Not really available for review today, but I took a quick glance and it looks very professional as usual. I'll take the time to review asap!

@ziima
Copy link
Collaborator Author

ziima commented Sep 14, 2018

No rush. I haven't yet tried it with any of our projects :)

README.rst Outdated
raise ValueError('%s must be a a string or a compiled regex '
'(use re.compile)' % name)
# Raise ValidationError
raise ValidationError('%s must be a string or a compiled regex (use re.compile)')
Copy link
Owner

@pawamoy pawamoy Sep 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, will Django populate the %s itself? I think it should be like what you wrote later:

                raise ValidationError('%(value)s is not a string or a compiled regex (use re.compile)',
                    params={'value': value})

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, moreover it's recommended way to raise a ValidationError, see https://docs.djangoproject.com/en/2.1/ref/forms/validation/#raising-validationerror

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you simply copy-paste it then 🙂 ? So both examples use the recommended way.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now I get the problem. Thanks :)

Copy link
Owner

@pawamoy pawamoy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great PR, thanks 🙂 Just a few questions/changes before merging, but nothing crazy.

docs/usage.rst Outdated

The second way is to subclass ``appsettings.Setting`` and write a custom
``checker`` method:
The most customization can be reached by customizing the ``validate()`` method.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The most customization sounds wrong, maybe something like The finest-grained customization can be obtained would be better? Or maybe you forgot a word?

More complex customization can be reached?

src/appsettings/settings.py Show resolved Hide resolved
self.validators.append(ValuesTypeValidator(item_type))
if empty is not None:
warnings.warn("Empty argument is deprecated, use min_length instead.", DeprecationWarning)
min_length = 1
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we check if empty is true or false? Deprecation is a thing, but the behavior should stay the same. If the user says empty is allowed (true), then min length should be 0 (or None, to avoid adding an unnecessary validator). If not (false), then indeed min length should be 1.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad, looks like I got ahead of myself.

call_default=call_default, transform_default=transform_default, validators=validators)
if empty is not None:
warnings.warn("Empty argument is deprecated, use min_length instead.", DeprecationWarning)
min_length = 1
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as for IterableSetting.

**checker_kwargs):
default_validators = (TypeValidator(list), )

def __init__(self, name='', default=list, **kwargs):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In previous classes you didn't use **kwargs, is there a reason? I like using **kwargs because avoids duplicated code, however it can decrease the ability of introspection (IDE popup with method's accepted arguments is my main example). So I'm not sure 😄 What do you think?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed, most of them now override the __init__ just to provide a different default value. I was hoping to solve that in subsequent PR. I've created #37, so I don't forget.

I have tried to use the **kwargs whenever possible as the number of arguments is quite large, and in this case I consider the duplication worse than missing introspection. In places where it's not used, new argument are appended.

Also I forgot about *args, so I wiil add them as well, in case somebody uses them.

self.validators.append(DictValuesTypeValidator(value_type))
if empty is not None:
warnings.warn("Empty argument is deprecated, use min_length instead.", DeprecationWarning)
min_length = 1
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as for IterableSetting and StringSetting.

empty (bool): whether empty iterable is allowed. Deprecated in favor of min_length.
"""
if key_type is not None:
warnings.warn("Argument key_type does nothing and is deprecated.", DeprecationWarning)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should it be deprecated?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't found any use case nor restriction to maintain it. Objects which can serve as a key in dictionary are limited to hashables by python and I don't actually see any benefits in further restriction.

I'm not very strong about this, so if you have any arguments to keep it, I'm open to reconsider.

Copy link
Owner

@pawamoy pawamoy Sep 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One could want to restrict the key type to int only:

# official django setting
MESSAGE_TAGS = {
    messages.DEBUG: 'default',
    messages.INFO: 'info',
    messages.SUCCESS: 'success',
    messages.WARNING: 'warning',
    messages.ERROR: 'danger',
}

Or any other hashable type, like a tuple.

NEURONAL_NETWORK = {
    (0, 0, 0): 1,
    (0, 0, 1): 0,
    ...
}

Since I'm going to manipulate the keys as well, I like the possibility to enforce their type so I don't have to do it manually.

Even if I never use the key_type, I just like to know that I can. Afterall we already have a DictValuesTypeValidator, so why not a DictKeysTypeValidator as well? It's only 14 lines of code 😛

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, The integers make a good point.

validators (list of callables): list of additional validators to use.
min_length (int): minimum length of the iterable (included).
max_length (int): maximum length of the iterable (included).
empty (bool): whether empty iterable is allowed. Deprecated in favor of min_length.
Copy link
Owner

@pawamoy pawamoy Sep 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do min_length and max_length make sense for the ObjectSetting? Maybe we should instead warn if they are present and pop them from the kwargs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, I don't see any point. That also applies to empty argument.

subsetting.check()
super(NestedSetting, self).check()
for subsetting in self.settings.values():
subsetting.check()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same remark as above, should we store exception messages and concatenate them before reraising?

@ziima
Copy link
Collaborator Author

ziima commented Sep 19, 2018

Round 1: fixed and rebased.

@pawamoy
Copy link
Owner

pawamoy commented Sep 19, 2018

Great thanks 🙂 Just three things left: simple copy-paste for the regex validation example in readme, your thoughts about a DictKeysTypeValidator, and warning + dict pop for min_length max_length and empty for the ObjectSetting.

@ziima
Copy link
Collaborator Author

ziima commented Sep 20, 2018

I have noticed the min_length and max_length in DictSettings. Do those make any sense? Shouldn't we remove them. I can't quite imagine any meaningful usage.

@ziima
Copy link
Collaborator Author

ziima commented Sep 20, 2018

Round 2: fixed and rebased.

Only the new comment about DictSettings should remain to be resolved.

@pawamoy
Copy link
Owner

pawamoy commented Sep 22, 2018

So, do you want to remove the min_length max_length and empty args for ObjectSetting and DictSetting in this PR? Or in another?

@ziima
Copy link
Collaborator Author

ziima commented Sep 24, 2018

I've already deprecated them from ObjectSetting in here, so I could do the DictSetting as well.

@pawamoy
Copy link
Owner

pawamoy commented Sep 24, 2018

Sure, please go on!

@ziima
Copy link
Collaborator Author

ziima commented Sep 25, 2018

Done. I've also added deprecation warning to TypeChecker.

@pawamoy
Copy link
Owner

pawamoy commented Sep 25, 2018

Perfect, let's merge it!

@pawamoy pawamoy merged commit db5f50e into pawamoy:master Sep 25, 2018
@stinovlas
Copy link
Collaborator

I tried these custom validators and they are working great! Would it be possible to make a new release? I could use dependency_links, but having release on PyPI is much more convenient =o).

@pawamoy
Copy link
Owner

pawamoy commented Dec 3, 2018

Great! Will do that today 🙂

@pawamoy
Copy link
Owner

pawamoy commented Dec 3, 2018

Done 😛

@stinovlas
Copy link
Collaborator

Done stuck_out_tongue

Thank you 😉!

@ziima ziima deleted the use-validators branch May 22, 2019 13:54
@pawamoy pawamoy mentioned this pull request Aug 12, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants